package com.pengxun.mall.service.impl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;
import com.pengxun.common.utils.NumberToCN;
import com.pengxun.mall.dao.OrderAddressDao;
import com.pengxun.mall.dao.OrderDao;
import com.pengxun.mall.dao.OrderGoodsDao;
import com.pengxun.mall.dao.OrderRemarkDao;
import com.pengxun.mall.dao.StoreDao;
import com.pengxun.mall.dto.ChangeOrderGoodsDTO;
import com.pengxun.mall.dto.OrderDTO;
import com.pengxun.mall.dto.OrderGoodsDTO;
import com.pengxun.mall.dto.OrderReportDTO;
import com.pengxun.mall.dto.SearchOrderDTO;
import com.pengxun.mall.dto.UpdateOrderDTO;
import com.pengxun.mall.model.Order;
import com.pengxun.mall.model.OrderAddress;
import com.pengxun.mall.model.OrderGoods;
import com.pengxun.mall.model.OrderRemark;
import com.pengxun.mall.model.Store;
import com.pengxun.mall.service.GoodsService;
import com.pengxun.mall.service.OrderService;
import com.pengxun.mall.vo.GoodsGroupPriceVO;
import com.pengxun.mall.vo.GoodsVO;
import com.pengxun.mall.vo.OrderAddressVO;
import com.pengxun.mall.vo.OrderGoodsVO;
import com.pengxun.mall.vo.OrderRemarkVO;
import com.pengxun.mall.vo.OrderReportVO;
import com.pengxun.mall.vo.OrderVO;
import com.szeastroc.common.constant.CommonStatus;
import com.szeastroc.common.exception.EastrocException;
import com.szeastroc.common.jdbc.crud.SqlBuilder;
import com.szeastroc.common.jdbc.page.Page;
import com.szeastroc.common.utils.CopyUtils;
import com.szeastroc.common.utils.ValidationUtils;

@Service
public class OrderServiceImpl implements OrderService {

	@Resource
	public OrderGoodsDao orderGoodsDao;

	@Resource
	private OrderDao orderDao;

	@Resource
	private GoodsService goodsService;

	@Resource
	private OrderAddressDao orderAddressDao;

	@Resource
	private OrderRemarkDao orderRemarkDao;

	@Resource
	private StoreDao storeDao;

	@Override
	@Transactional
	public void createOrder(OrderDTO orderDTO) {
		ValidationUtils.validate(orderDTO);

		Store store = storeDao.findFirst(new SqlBuilder(Store.class).eq("id", orderDTO.getStoreId()).build());

		if (store == null) {
			throw new EastrocException("店铺不存在");
		}

		if (CollectionUtils.isEmpty(orderDTO.getOrderGoodses())) {
			throw new EastrocException("商品不能为空");
		}

		String orderNum = generateOrderNum();

		List<OrderGoods> orderGoodses = orderDTO.getOrderGoodses().stream().map(p -> {
			GoodsVO goodsVO = goodsService.findById(p.getGoodsId());
			OrderGoods orderGoods = CopyUtils.copyBean(goodsVO, OrderGoods.class);
			orderGoods.setOrderNum(orderNum);
			orderGoods.setAmount(p.getAmount());
			orderGoods.setId(null);
			orderGoods.setGoodsId(goodsVO.getId());
			orderGoods.setCostPrice(goodsVO.getPrice());
			Optional<GoodsGroupPriceVO> optional = goodsVO.getGoodsGroupPrices().stream()
					.filter(l -> l.getGroupId().equals(store.getGroupId())).findFirst();
			if (!optional.isPresent()) {
				throw new EastrocException("商品" + goodsVO.getName() + "未配置价格");
			}

			orderGoods.setPrice(optional.get().getPrice());
			return orderGoods;
		}).collect(Collectors.toList());

		orderGoodsDao.batchInsert(orderGoodses);

		OrderAddress orderAddress = CopyUtils.copyBean(store, OrderAddress.class);
		orderAddress.setOrderNum(orderNum);

		orderAddressDao.insert(orderAddress);

		Order order = new Order();
		order.setOrderNum(orderNum);
		order.setPrintStatus(CommonStatus.NO.getCode().toString());
		order.setTotalMoney(orderGoodses.stream().map(p -> p.getPrice().multiply(new BigDecimal(p.getAmount())))
				.reduce(BigDecimal.ZERO, BigDecimal::add));
		order.setCostMoney(orderGoodses.stream().map(p -> p.getCostPrice().multiply(new BigDecimal(p.getAmount())))
				.reduce(BigDecimal.ZERO, BigDecimal::add));
		order.setStoreId(store.getId());
		order.setStatus(CommonStatus.NO.getCode().toString());

		orderDao.insert(order);

	}

	private String generateOrderNum() {
		String maxOrderNum = orderDao.getMaxOrdernum();

		if (StringUtils.isEmpty(maxOrderNum)) {
			return DateTime.now().toString("yyyyMMddHH") + "0000";
		}

		Integer orderNum = Integer.parseInt(maxOrderNum.replaceAll(DateTime.now().toString("yyyyMMddHH"), "")) + 1;
		return DateTime.now().toString("yyyyMMddHH") + StringUtils.leftPad(String.valueOf(orderNum), 4, "0");
	}



	@Override
	public Page getOrders(SearchOrderDTO searchOrderDTO) {

		List<Order> orders = orderDao.getOrders(searchOrderDTO);

		if (CollectionUtils.isEmpty(orders)) {
			return new Page();
		}

		Page page = new Page();
		BeanUtils.copyProperties(searchOrderDTO, page);

		page.setData(orders.stream().map(p -> {
			return builderOrderVO(p);
		}).collect(Collectors.toList()));
		return page;
	}

	private OrderVO builderOrderVO(Order order) {
		OrderVO orderVO = CopyUtils.copyBean(order, OrderVO.class);

		OrderAddress orderAddress = orderAddressDao
				.findFirst(new SqlBuilder(OrderAddress.class).eq("orderNum", order.getOrderNum()).build());

		orderVO.setOrderAddress(CopyUtils.copyBean(orderAddress, OrderAddressVO.class));

		List<OrderGoods> orderGoodses = orderGoodsDao
				.findBy(new SqlBuilder(OrderGoods.class).eq("orderNum", order.getOrderNum()).build());

		List<OrderGoodsVO> orderGoodsVOs = CopyUtils.copyList(orderGoodses, OrderGoodsVO.class);

		orderGoodsVOs.forEach(p -> {
			p.setTotalMoney(p.getPrice().multiply(new BigDecimal(p.getAmount())));

		});

		orderVO.setOrderGoodses(orderGoodsVOs);
		orderVO.setTotalMoneyCN(NumberToCN.number2CNMontrayUnit(orderVO.getTotalMoney()));
		orderVO.setTotalAmount(orderGoodsVOs.stream().mapToInt(p -> p.getAmount()).sum());

		List<OrderRemark> orderRemarks = orderRemarkDao
				.findAll(new SqlBuilder(OrderRemark.class).eq("orderNum", order.getOrderNum()).build());

		if (!CollectionUtils.isEmpty(orderRemarks)) {
			orderVO.setOrderRemarks(CopyUtils.copyList(orderRemarks, OrderRemarkVO.class));
		}

		return orderVO;
	}

	@Override
	public void updateOrder(UpdateOrderDTO updateOrderDTO) {
		ValidationUtils.validate(updateOrderDTO);

		Order order = CopyUtils.copyBean(updateOrderDTO, Order.class);
		orderDao.updateBy(order, "orderNum");

	}

	@Override
	public OrderVO getOrderDetail(String orderNum) {

		Order order = orderDao.findFirst(new SqlBuilder(Order.class).eq("orderNum", orderNum).build());

		if (order == null) {
			throw new EastrocException("订单不存在");
		}

		return builderOrderVO(order);
	}

	@Override
	public void changeOrderGoods(ChangeOrderGoodsDTO changeOrderGoodsDTO) {

		ValidationUtils.validate(changeOrderGoodsDTO);

		if (!CollectionUtils.isEmpty(changeOrderGoodsDTO.getOrderGoodses())) {
			for (OrderGoodsDTO orderGoodsDTO : changeOrderGoodsDTO.getOrderGoodses()) {
				if (orderGoodsDTO.getAmount() == 0) {
					orderGoodsDao
							.deleteBy(new SqlBuilder(OrderGoods.class).eq("orderNum", changeOrderGoodsDTO.getOrderNum())
									.eq("goodsId", orderGoodsDTO.getGoodsId()).build());
				} else {
					OrderGoods orderGoods = CopyUtils.copyBean(orderGoodsDTO, OrderGoods.class);
					orderGoods.setOrderNum(changeOrderGoodsDTO.getOrderNum());
					orderGoodsDao.updateBy(orderGoods, "orderNum", "goodsId");
				}
			}
		}

		cacluateOrder(changeOrderGoodsDTO.getOrderNum());

	}

	private void cacluateOrder(String orderNum) {
		List<OrderGoods> orderGoodses = orderGoodsDao
				.findBy(new SqlBuilder(OrderGoods.class).eq("orderNum", orderNum).build());
		Order order = new Order();
		order.setOrderNum(orderNum);
		order.setTotalMoney(orderGoodses.stream().map(p -> p.getPrice().multiply(new BigDecimal(p.getAmount())))
				.reduce(BigDecimal.ZERO, BigDecimal::add));
		order.setCostMoney(orderGoodses.stream().map(p -> p.getCostPrice().multiply(new BigDecimal(p.getAmount())))
				.reduce(BigDecimal.ZERO, BigDecimal::add));
		orderDao.updateBy(order, "orderNum");
	}

	@Override
	public OrderReportVO getOrderReport(OrderReportDTO orderReportDTO) {
		try {
			ValidationUtils.validate(orderReportDTO);
		} catch (Exception e) {
			return null;
		}

		orderReportDTO.setEndTime(new DateTime(orderReportDTO.getEndTime()).toDate());
		List<OrderGoods> orderGoods = orderGoodsDao.getOrderReport(orderReportDTO);

		if (CollectionUtils.isEmpty(orderGoods)) {
			OrderReportVO orderReportVO = new OrderReportVO();
			orderReportVO.setCostMoney(new BigDecimal(0));
			orderReportVO.setTotalMoney(new BigDecimal(0));
			orderReportVO.setProfitsMoney(new BigDecimal(0));
			orderReportVO.setOrderGoodses(Lists.newArrayList());
			return orderReportVO;
		}

		OrderReportVO orderReportVO = new OrderReportVO();
		orderReportVO.setOrderGoodses(CopyUtils.copyList(orderGoods, OrderGoodsVO.class));

		orderReportVO.setTotalMoney(
				orderReportVO.getOrderGoodses().stream().map(p -> p.getPrice().multiply(new BigDecimal(p.getAmount())))
						.reduce(BigDecimal.ZERO, BigDecimal::add));
		orderReportVO.setCostMoney(orderReportVO.getOrderGoodses().stream()
				.map(p -> p.getCostPrice().multiply(new BigDecimal(p.getAmount())))
				.reduce(BigDecimal.ZERO, BigDecimal::add));

		orderReportVO.setProfitsMoney(orderReportVO.getTotalMoney().subtract(orderReportVO.getCostMoney()));

		return orderReportVO;
	}
}
